package com.zzyl.intercept;

import com.zzyl.constant.Constants;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.properties.JwtProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @className: WeChatLoginInterceptor
 * @description:
 * @author: InnovatorX
 * @date: 2024/5/29 20:24
 * @Version: 1.0
 */
@Slf4j
@Component
public class WeChatLoginInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 在请求处理之前进行拦截。在这个方法中可以进行一些预处理的工作，比如日志记录、权限检查等。
     * 如果返回false，则不会继续执行Handler，即拦截请求；如果返回true，则会继续执行Handler。
     * 获取Token,获取userId
     * 放入到ThreadLocal中
     *
     * @param request  HttpServletRequest对象，代表客户端的请求
     * @param response HttpServletResponse对象，用于向客户端发送响应
     * @param handler  将要执行的Handler对象
     * @return boolean 返回一个布尔值，决定是否继续执行Handler
     * @throws Exception 抛出异常时可捕获
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求的URL
        String url = request.getRequestURI();
        log.info("拦截请求:{}",url);

        // 判断是否登录,就放行
        if ("/customer/user/login".equals(url)){
            return true;
        }

        // 从头中 key authorization 获取token
        String token = request.getHeader("authorization");
        log.info("哈哈token:{}",token);

        // 判断token是否有值
        if (StringUtils.isBlank(token)){
            log.error("token为空");
            throw new BaseException(BasicEnum.LOGIN_LOSE_EFFICACY);
        }

        // 解析token,获取userId
        Map<String, Object> map = JwtUtil.parseJWT(jwtProperties.getBase64EncodedSecretKey(),token);
        log.info("获取的userId为:  map:{}",map);
        if (map == null || map.isEmpty()){
            log.error("token无效");
            throw new BaseException(BasicEnum.LOGIN_LOSE_EFFICACY);
        }

        // 把userId放入ThreadLocal
        UserThreadLocal.setSubject(map.get(Constants.JWT_USERNAME).toString());
        Long userId= Long.parseLong(map.get(Constants.JWT_USERID).toString());
        UserThreadLocal.set(userId);
        return true;

    }

    /**
     * 在Handler执行完成后，生成响应之前进行拦截。在这个方法中可以进行一些后处理的工作，比如日志记录、统计处理时间等。
     * 移除ThreadLocal中的数据
     *
     * @param request      HttpServletRequest对象，代表客户端的请求
     * @param response     HttpServletResponse对象，用于向客户端发送响应
     * @param handler      执行的Handler对象
     * @param modelAndView Handler执行后返回的ModelAndView对象，如果Handler没有返回ModelAndView，则为null
     * @throws Exception 抛出异常时可捕获
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 在整个请求处理完成后，即视图渲染完成后进行拦截。在这个方法中可以进行一些资源释放、日志记录等操作。
     *
     * @param request  HttpServletRequest对象，代表客户端的请求
     * @param response HttpServletResponse对象，用于向客户端发送响应
     * @param handler  执行的Handler对象
     * @param ex       在Handler执行过程中抛出的异常，如果没异常则为null
     * @throws Exception 抛出异常时可捕获
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
